home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / stunnel-4.04 / _src / src / ssl.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-01  |  16.3 KB  |  517 lines

  1. /*
  2.  *   stunnel       Universal SSL tunnel
  3.  *   Copyright (c) 1998-2002 Michal Trojnara <Michal.Trojnara@mirt.net>
  4.  *                 All Rights Reserved
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 2 of the License, or
  9.  *   (at your option) any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   In addition, as a special exception, Michal Trojnara gives
  21.  *   permission to link the code of this program with the OpenSSL
  22.  *   library (or with modified versions of OpenSSL that use the same
  23.  *   license as OpenSSL), and distribute linked combinations including
  24.  *   the two.  You must obey the GNU General Public License in all
  25.  *   respects for all of the code used other than OpenSSL.  If you modify
  26.  *   this file, you may extend this exception to your version of the
  27.  *   file, but you are not obligated to do so.  If you do not wish to
  28.  *   do so, delete this exception statement from your version.
  29.  */
  30. #ifdef __vms
  31. #include <starlet.h>
  32. #endif /* __vms */
  33.  
  34. #ifndef NO_RSA
  35.  
  36. /* Cache temporary keys up to 2048 bits */
  37. #define KEY_CACHE_LENGTH 2049
  38.  
  39. /* Cache temporary keys up to 1 hour */
  40. #define KEY_CACHE_TIME 3600
  41.  
  42. #endif /* NO_RSA */
  43.  
  44. #include "common.h"
  45. #include "prototypes.h"
  46.  
  47.     /* SSL functions */
  48. static int init_dh(void);
  49. static int init_prng(void);
  50. static int prng_seeded(int);
  51. static int add_rand_file(char *);
  52. #ifndef NO_RSA
  53. static RSA *tmp_rsa_cb(SSL *, int, int);
  54. static RSA *make_temp_key(int);
  55. #endif /* NO_RSA */
  56. static void verify_init(void);
  57. static int verify_callback(int, X509_STORE_CTX *);
  58. #if SSLEAY_VERSION_NUMBER >= 0x00907000L
  59. static void info_callback(const SSL *, int, int);
  60. #else
  61. static void info_callback(SSL *, int, int);
  62. #endif
  63. static void print_stats(void);
  64. static void sslerror_stack(void);
  65.  
  66. SSL_CTX *ctx; /* global SSL context */
  67.  
  68. void context_init(void) { /* init SSL */
  69.     int i;
  70.  
  71.     if(!init_prng())
  72.         log(LOG_INFO, "PRNG seeded successfully");
  73.     SSLeay_add_ssl_algorithms();
  74.     SSL_load_error_strings();
  75.     if(options.option.client) {
  76.         ctx=SSL_CTX_new(SSLv3_client_method());
  77.     } else { /* Server mode */
  78.         ctx=SSL_CTX_new(SSLv23_server_method());
  79. #ifndef NO_RSA
  80.         SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
  81. #endif /* NO_RSA */
  82.         if(init_dh())
  83.             log(LOG_WARNING, "Diffie-Hellman initialization failed");
  84.     }
  85.     if(options.ssl_options) {
  86.         log(LOG_DEBUG, "Configuration SSL options: 0x%08lX",
  87.             options.ssl_options);
  88.         log(LOG_DEBUG, "SSL options set: 0x%08lX", 
  89.             SSL_CTX_set_options(ctx, options.ssl_options));
  90.     }
  91. #if SSLEAY_VERSION_NUMBER >= 0x00906000L
  92.     SSL_CTX_set_mode(ctx,
  93.         SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  94. #endif /* OpenSSL-0.9.6 */
  95.  
  96.     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
  97.     SSL_CTX_set_timeout(ctx, options.session_timeout);
  98.     if(options.option.cert) {
  99.         if(!SSL_CTX_use_certificate_chain_file(ctx, options.cert)) {
  100.             log(LOG_ERR, "Error reading certificate file: %s", options.cert);
  101.             sslerror("SSL_CTX_use_certificate_chain_file");
  102.             exit(1);
  103.         }
  104.         log(LOG_DEBUG, "Certificate: %s", options.cert);
  105.         log(LOG_DEBUG, "Key file: %s", options.key);
  106. #ifdef USE_WIN32
  107.         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
  108. #endif
  109.         for(i=0; i<3; i++) {
  110. #ifdef NO_RSA
  111.             if(SSL_CTX_use_PrivateKey_file(ctx, options.key,
  112.                     SSL_FILETYPE_PEM))
  113. #else /* NO_RSA */
  114.             if(SSL_CTX_use_RSAPrivateKey_file(ctx, options.key,
  115.                     SSL_FILETYPE_PEM))
  116. #endif /* NO_RSA */
  117.                 break;
  118.             if(i<2 && ERR_GET_REASON(ERR_peek_error())==EVP_R_BAD_DECRYPT) {
  119.                 sslerror_stack(); /* dump the error stack */
  120.                 log(LOG_ERR, "Wrong pass phrase: retrying");
  121.                 continue;
  122.             }
  123. #ifdef NO_RSA
  124.             sslerror("SSL_CTX_use_PrivateKey_file");
  125. #else /* NO_RSA */
  126.             sslerror("SSL_CTX_use_RSAPrivateKey_file");
  127. #endif /* NO_RSA */
  128.             exit(1);
  129.         }
  130.         if(!SSL_CTX_check_private_key(ctx)) {
  131.             sslerror("Private key does not match the certificate");
  132.             exit(1);
  133.         }
  134.     }
  135.  
  136.     verify_init(); /* Initialize certificate verification */
  137.  
  138.     SSL_CTX_set_info_callback(ctx, info_callback);
  139.  
  140.     if(options.cipher_list) {
  141.         if (!SSL_CTX_set_cipher_list(ctx, options.cipher_list)) {
  142.             sslerror("SSL_CTX_set_cipher_list");
  143.             exit(1);
  144.         }
  145.     }
  146. }
  147.  
  148. void context_free(void) { /* free SSL */
  149.     SSL_CTX_free(ctx);
  150. }
  151.  
  152. static int init_prng(void) {
  153.     int totbytes=0;
  154.     char filename[STRLEN];
  155.     int bytes;
  156.     
  157.     bytes=0; /* avoid warning if #ifdef'd out for windows */
  158.  
  159.     filename[0]='\0';
  160.  
  161.     /* If they specify a rand file on the command line we
  162.        assume that they really do want it, so try it first */
  163.     if(options.rand_file) {
  164.         totbytes+=add_rand_file(options.rand_file);
  165.         if(prng_seeded(totbytes))
  166.             return 0;
  167.     }
  168.  
  169.     /* try the $RANDFILE or $HOME/.rnd files */
  170.     RAND_file_name(filename, STRLEN);
  171.     if(filename[0]) {
  172.         filename[STRLEN-1]='\0';        /* just in case */
  173.         totbytes+=add_rand_file(filename);
  174.         if(prng_seeded(totbytes))
  175.             return 0;
  176.     }
  177.  
  178. #ifdef RANDOM_FILE
  179.     totbytes += add_rand_file( RANDOM_FILE );
  180.     if(prng_seeded(totbytes))
  181.         return 0;
  182. #endif
  183.  
  184. #ifdef USE_WIN32
  185.     RAND_screen();
  186.     if(prng_seeded(totbytes)) {
  187.         log(LOG_DEBUG, "Seeded PRNG with RAND_screen");
  188.         return 0;
  189.     }
  190.     log(LOG_DEBUG, "RAND_screen failed to sufficiently seed PRNG");
  191. #else
  192.  
  193. #if SSLEAY_VERSION_NUMBER >= 0x0090581fL
  194.     if(options.egd_sock) {
  195.         if((bytes=RAND_egd(options.egd_sock))==-1) {
  196.             log(LOG_WARNING, "EGD Socket %s failed", options.egd_sock);
  197.             bytes=0;
  198.         } else {
  199.             totbytes += bytes;
  200.             log(LOG_DEBUG, "Snagged %d random bytes from EGD Socket %s",
  201.                 bytes, options.egd_sock);
  202.             return 0; /* OpenSSL always gets what it needs or fails,
  203.                          so no need to check if seeded sufficiently */
  204.         }
  205.     }
  206. #ifdef EGD_SOCKET
  207.     if((bytes=RAND_egd(EGD_SOCKET))==-1) {
  208.         log(LOG_WARNING, "EGD Socket %s failed", EGD_SOCKET);
  209.     } else {
  210.         totbytes += bytes;
  211.         log(LOG_DEBUG, "Snagged %d random bytes from EGD Socket %s",
  212.             bytes, EGD_SOCKET);
  213.         return 0;
  214.     }
  215. #endif /* EGD_SOCKET */
  216.  
  217. #endif /* OpenSSL-0.9.5a */
  218. #endif /* USE_WIN32 */
  219.  
  220.     /* Try the good-old default /dev/urandom, if available  */
  221.     totbytes+=add_rand_file( "/dev/urandom" );
  222.     if(prng_seeded(totbytes))
  223.         return 0;
  224.  
  225.     /* Random file specified during configure */
  226.     log(LOG_INFO, "PRNG seeded with %d bytes total", totbytes);
  227.     log(LOG_WARNING, "PRNG may not have been seeded with enough random bytes");
  228.     return -1; /* FAILED */
  229. }
  230.  
  231. static int init_dh(void) {
  232. #ifdef USE_DH
  233.     FILE *fp;
  234.     DH *dh;
  235.     BIO *bio;
  236.  
  237.     fp=fopen(options.cert, "r");
  238.     if(!fp) {
  239. #ifdef USE_WIN32
  240.         /* Win32 doesn't seem to set errno in fopen() */
  241.         log(LOG_ERR, "Failed to open %s", options.cert);
  242. #else
  243.         ioerror(options.cert);
  244. #endif
  245.         return -1; /* FAILED */
  246.     }
  247.     bio=BIO_new_fp(fp, BIO_CLOSE|BIO_FP_TEXT);
  248.     if(!bio) {
  249.         log(LOG_ERR, "BIO_new_fp failed");
  250.         return -1; /* FAILED */
  251.     }
  252.     if((dh=PEM_read_bio_DHparams(bio, NULL, NULL
  253. #if SSLEAY_VERSION_NUMBER >= 0x00904000L
  254.             , NULL
  255. #endif
  256.             ))) {
  257.         BIO_free(bio);
  258.         log(LOG_DEBUG, "Using Diffie-Hellman parameters from %s",
  259.             options.cert);
  260.     } else { /* Failed to load DH parameters from file */
  261.         BIO_free(bio);
  262.         log(LOG_NOTICE, "Could not load DH parameters from %s", options.cert);
  263.         return -1; /* FAILED */
  264.     }
  265.     SSL_CTX_set_tmp_dh(ctx, dh);
  266.     log(LOG_INFO, "Diffie-Hellman initialized with %d bit key",
  267.         8*DH_size(dh));
  268.     DH_free(dh);
  269. #endif /* USE_DH */
  270.     return 0; /* OK */
  271. }
  272.  
  273. /* shortcut to determine if sufficient entropy for PRNG is present */
  274. static int prng_seeded(int bytes) {
  275. #if SSLEAY_VERSION_NUMBER >= 0x0090581fL
  276.     if(RAND_status()){
  277.         log(LOG_DEBUG, "RAND_status claims sufficient entropy for the PRNG");
  278.         return 1;
  279.     }
  280. #else
  281.     if(bytes>=options.random_bytes) {
  282.         log(LOG_INFO, "Sufficient entropy in PRNG assumed (>= %d)", options.random_bytes);
  283.         return 1;
  284.     }
  285. #endif
  286.     return 0;        /* assume we don't have enough */
  287. }
  288.  
  289. static int add_rand_file(char *filename) {
  290.     int readbytes;
  291.     int writebytes;
  292.     struct stat sb;
  293.  
  294.     if(stat(filename, &sb))
  295.         return 0;
  296.     if((readbytes=RAND_load_file(filename, options.random_bytes)))
  297.         log(LOG_DEBUG, "Snagged %d random bytes from %s", readbytes, filename);
  298.     else
  299.         log(LOG_INFO, "Unable to retrieve any random data from %s", filename);
  300.     /* Write new random data for future seeding if it's a regular file */
  301.     if(options.option.rand_write && (sb.st_mode & S_IFREG)){
  302.         writebytes = RAND_write_file(filename);
  303.         if(writebytes==-1)
  304.             log(LOG_WARNING, "Failed to write strong random data to %s - "
  305.                 "may be a permissions or seeding problem", filename);
  306.         else
  307.             log(LOG_DEBUG, "Wrote %d new random bytes to %s", writebytes, filename);
  308.     }
  309.     return readbytes;
  310. }
  311.  
  312. #ifndef NO_RSA
  313.  
  314. static RSA *tmp_rsa_cb(SSL *s, int export, int keylen) {
  315.     static int initialized=0;
  316.     static struct keytabstruct {
  317.         RSA *key;
  318.         time_t timeout;
  319.     } keytable[KEY_CACHE_LENGTH];
  320.     static RSA *longkey=NULL;
  321.     static int longlen=0;
  322.     static time_t longtime=0;
  323.     RSA *oldkey, *retval;
  324.     time_t now;
  325.     int i;
  326.  
  327.     enter_critical_section(CRIT_KEYGEN); /* Only one make_temp_key() at a time */
  328.     if(!initialized) {
  329.         for(i=0; i<KEY_CACHE_LENGTH; i++) {
  330.             keytable[i].key=NULL;
  331.             keytable[i].timeout=0;
  332.         }
  333.         initialized=1;
  334.     }
  335.     time(&now);
  336.     if(keylen<KEY_CACHE_LENGTH) {
  337.         if(keytable[keylen].timeout<now) {
  338.             oldkey=keytable[keylen].key;
  339.             keytable[keylen].key=make_temp_key(keylen);
  340.             keytable[keylen].timeout=now+KEY_CACHE_TIME;
  341.             if(oldkey)
  342.                 RSA_free(oldkey);
  343.         }
  344.         retval=keytable[keylen].key;
  345.     } else { /* Temp key > 2048 bits.  Is it possible? */
  346.         if(longtime<now || longlen!=keylen) {
  347.             oldkey=longkey;
  348.             longkey=make_temp_key(keylen);
  349.             longtime=now+KEY_CACHE_TIME;
  350.             longlen=keylen;
  351.             if(oldkey)
  352.                 RSA_free(oldkey);
  353.         }
  354.         retval=longkey;
  355.     }
  356.     leave_critical_section(CRIT_KEYGEN);
  357.     return retval;
  358. }
  359.  
  360. static RSA *make_temp_key(int keylen) {
  361.     RSA *result;
  362.  
  363.     log(LOG_DEBUG, "Generating %d bit temporary RSA key...", keylen);
  364. #if SSLEAY_VERSION_NUMBER >= 0x0900
  365.     result=RSA_generate_key(keylen, RSA_F4, NULL, NULL);
  366. #else
  367.     result=RSA_generate_key(keylen, RSA_F4, NULL);
  368. #endif
  369.     log(LOG_DEBUG, "Temporary RSA key created");
  370.     return result;
  371. }
  372.  
  373. #endif /* NO_RSA */
  374.  
  375. static void verify_init(void) {
  376.     if(options.verify_level<0)
  377.         return; /* No certificate verification */
  378.  
  379.     if(options.verify_level>1 && !options.ca_file && !options.ca_dir) {
  380.         log(LOG_ERR, "Either CApath or CAfile "
  381.             "has to be used for authentication");
  382.         exit(1);
  383.     }
  384.  
  385.     if(options.ca_file) {
  386.         if(!SSL_CTX_load_verify_locations(ctx, options.ca_file, NULL)) {
  387.             log(LOG_ERR, "Error loading verify certificates from %s",
  388.                 options.ca_file);
  389.             sslerror("SSL_CTX_load_verify_locations");
  390.             exit(1);
  391.         }
  392. #if 0
  393.         SSL_CTX_set_client_CA_list(ctx,
  394.             SSL_load_client_CA_file(options.ca_file));
  395. #endif
  396.         log(LOG_DEBUG, "Loaded verify certificates from %s",
  397.             options.ca_file);
  398.     }
  399.  
  400.     if(options.ca_dir) {
  401.         if(!SSL_CTX_load_verify_locations(ctx, NULL, options.ca_dir)) {
  402.             log(LOG_ERR, "Error setting verify directory to %s",
  403.                 options.ca_dir);
  404.             sslerror("SSL_CTX_load_verify_locations");
  405.             exit(1);
  406.         }
  407.         log(LOG_DEBUG, "Set verify directory to %s", options.ca_dir);
  408.     }
  409.  
  410.     SSL_CTX_set_verify(ctx, options.verify_level==SSL_VERIFY_NONE ?
  411.         SSL_VERIFY_PEER : options.verify_level, verify_callback);
  412.  
  413.     if (options.verify_use_only_my)
  414.         log(LOG_NOTICE, "Peer certificate location %s", options.ca_dir);
  415. }
  416.  
  417. static int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx) {
  418.         /* our verify callback function */
  419.     char txt[STRLEN];
  420.     X509_OBJECT ret;
  421.  
  422.     X509_NAME_oneline(X509_get_subject_name(callback_ctx->current_cert),
  423.         txt, STRLEN);
  424.     safestring(txt);
  425.     if(options.verify_level==SSL_VERIFY_NONE) {
  426.         log(LOG_NOTICE, "VERIFY IGNORE: depth=%d, %s",
  427.             callback_ctx->error_depth, txt);
  428.         return 1; /* Accept connection */
  429.     }
  430.     if(!preverify_ok) {
  431.         /* Remote site specified a certificate, but it's not correct */
  432.         log(LOG_WARNING, "VERIFY ERROR: depth=%d, error=%s: %s",
  433.             callback_ctx->error_depth,
  434.             X509_verify_cert_error_string (callback_ctx->error), txt);
  435.         return 0; /* Reject connection */
  436.     }
  437.     if(options.verify_use_only_my && callback_ctx->error_depth==0 &&
  438.             X509_STORE_get_by_subject(callback_ctx, X509_LU_X509,
  439.                 X509_get_subject_name(callback_ctx->current_cert), &ret)!=1) {
  440.         log(LOG_WARNING, "VERIFY ERROR ONLY MY: no cert for %s", txt);
  441.         return 0; /* Reject connection */
  442.     }
  443.     log(LOG_NOTICE, "VERIFY OK: depth=%d, %s", callback_ctx->error_depth, txt);
  444.     return 1; /* Accept connection */
  445. }
  446.  
  447. #if SSLEAY_VERSION_NUMBER >= 0x00907000L
  448. static void info_callback(const SSL *s, int where, int ret) {
  449. #else
  450. static void info_callback(SSL *s, int where, int ret) {
  451. #endif
  452.     if(where & SSL_CB_LOOP)
  453.         log(LOG_DEBUG, "SSL state (%s): %s",
  454.         where & SSL_ST_CONNECT ? "connect" :
  455.         where & SSL_ST_ACCEPT ? "accept" :
  456.         "undefined", SSL_state_string_long(s));
  457.     else if(where & SSL_CB_ALERT)
  458.         log(LOG_DEBUG, "SSL alert (%s): %s: %s",
  459.             where & SSL_CB_READ ? "read" : "write",
  460.             SSL_alert_type_string_long(ret),
  461.             SSL_alert_desc_string_long(ret));
  462.     else if(where==SSL_CB_HANDSHAKE_DONE)
  463.         print_stats();
  464. }
  465.  
  466. static void print_stats(void) { /* print statistics */
  467.     log(LOG_DEBUG, "%4ld items in the session cache",
  468.         SSL_CTX_sess_number(ctx));
  469.     log(LOG_DEBUG, "%4ld client connects (SSL_connect())",
  470.         SSL_CTX_sess_connect(ctx));
  471.     log(LOG_DEBUG, "%4ld client connects that finished",
  472.         SSL_CTX_sess_connect_good(ctx));
  473. #if SSLEAY_VERSION_NUMBER >= 0x0922
  474.     log(LOG_DEBUG, "%4ld client renegotiatations requested",
  475.         SSL_CTX_sess_connect_renegotiate(ctx));
  476. #endif
  477.     log(LOG_DEBUG, "%4ld server connects (SSL_accept())",
  478.         SSL_CTX_sess_accept(ctx));
  479.     log(LOG_DEBUG, "%4ld server connects that finished",
  480.         SSL_CTX_sess_accept_good(ctx));
  481. #if SSLEAY_VERSION_NUMBER >= 0x0922
  482.     log(LOG_DEBUG, "%4ld server renegotiatiations requested",
  483.         SSL_CTX_sess_accept_renegotiate(ctx));
  484. #endif
  485.     log(LOG_DEBUG, "%4ld session cache hits", SSL_CTX_sess_hits(ctx));
  486.     log(LOG_DEBUG, "%4ld session cache misses", SSL_CTX_sess_misses(ctx));
  487.     log(LOG_DEBUG, "%4ld session cache timeouts", SSL_CTX_sess_timeouts(ctx));
  488. }
  489.  
  490. void sslerror(char *txt) { /* SSL Error handler */
  491.     unsigned long err;
  492.     char string[120];
  493.  
  494.     err=ERR_get_error();
  495.     if(!err) {
  496.         log(LOG_ERR, "%s: Peer suddenly disconnected", txt);
  497.         return;
  498.     }
  499.     sslerror_stack();
  500.     ERR_error_string(err, string);
  501.     log(LOG_ERR, "%s: %lX: %s", txt, err, string);
  502. }
  503.  
  504. static void sslerror_stack(void) { /* recursive dump of the error stack */
  505.     unsigned long err;
  506.     char string[120];
  507.  
  508.     err=ERR_get_error();
  509.     if(!err)
  510.         return;
  511.     sslerror_stack();
  512.     ERR_error_string(err, string);
  513.     log(LOG_ERR, "error stack: %lX : %s", err, string);
  514. }
  515.  
  516. /* End of ssl.c */
  517.